package org.example.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * 演示 @Value , Environment 获取 yml 中的配置属性值
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2021/8/8 9:53
 */
@RestController
@SuppressWarnings("all")
public class ValueController {

    // 直接从容器中获取即可, Spring 框架已经默认提供了.
    @Autowired
    private Environment environment;

    // 通过Environment的getProperty方法获取配置，其他实例对象也是同理
    @Value("#{environment.getProperty('server.port', '80')}")
    private String serverPort;

    // 如果是调用静态方法，则需要加T(包名).方法名称)。
    @Value("#{T(java.lang.Math).random() * 1000}")
    private double randomValue;

    //赋值普通的Java数据类型值
    @Value("v2.3.1")
    private String version;

    //${key}：从环境变量以及配置文件中取值，如果值不存在，则设置分号后面的默认值
    @Value(value = "${app.info.str:xxx}")
    private String str;

    @Value("${app.info.int:0}")
    private int integer;

    @Value("${app.info.date:1993/08/20}")
    private Date date;

    //数组可以直接取值，不存在时使用分号后面的默认值，分号后面什么都没有时，表示数组为空数组，长度为0
    @Value("${app.info.array1:}")
    private String[] array1;

    @Value("${app.info.array2:A,B,C}")
    private String[] array2;

    //#{SpEL}：Spring 表达式语言
    @Value("#{20.5* 1000}")
    private float salary;

    /**
     * @Value 注解无法直接注入 List 类型，必须通过数组 + SpEl 表达式语言进行转换
     * 第一个 $ 取值表示如果不存在，则数组默认为空，当数组为空(.empty)，则让 list 默认为空，
     * 否则不为空时，使用 split 函数用逗号将数组分割转为 list.
     */
    @Value("#{'${app.info.arrayToList:}'.empty ? '': '${app.info.arrayToList:}'.split(',')}")
    private List<String> list;

    /**
     * @Value 注解无法直接注入 Set 类型，必须通过数组 + SpEl 表达式语言进行转换
     * 第一个 $ 取值表示如果不存在，则数组默认为空，当数组为空(.empty)，则让 Set 默认为：大汉,大隋，
     * 否则不为空时，使用 split 函数用逗号将数组分割转为 Set.
     * set 操作与 list 完全一样，只是 set 会自动去重.
     */
    @Value("#{'${app.info.arrayToList:}'.empty ? '大汉,大隋': '${app.info.arrayToList:}'.split(',')}")
    private Set<String> set;

    //@Value 获取 Map 属性时，暂时不知道如何设置默认值
    @Value("#{${app.info.cityMap}}")
    private Map<String, Object> map;

    /**
     * 获取服务端口，不配置时，默认为 80
     * [@Value] 注解在服务启动时就会自动注入，所以被标记的方法在服务启动时就会自动执行
     *
     * @param dbDriver
     */
    @Value("${server.port:80}")
    private void getServerPort(String serverPort) {
        System.out.println("服务端口(serverPort)=" + serverPort);
    }

    /**
     * http://localhost:8080/value/get
     *
     * @return
     */
    @GetMapping("value/get")
    public Map<String, Object> getValue() {
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("version", version);
        resultMap.put("str", str);
        resultMap.put("integer", integer);
        resultMap.put("date", date);
        resultMap.put("array1", array1);
        resultMap.put("array2", array2);
        resultMap.put("salary", salary);
        resultMap.put("list", list);
        resultMap.put("set", set);
        resultMap.put("map", map);
        resultMap.put("randomValue", randomValue);
        resultMap.put("serverPort", serverPort);

        System.out.println(resultMap);
        return resultMap;
    }

    /**
     * {@link Environment} 表示环境, 可用于获取应用程序的属性配置.
     * String getProperty(String key): 返回全局配置文件中与给定 key 关联的属性值, 如果没有,则返回 null.
     * <p>
     * http://localhost:8080/value/environment
     */
    @GetMapping("value/environment")
    public Map<String, Object> environment() {
        Map<String, Object> resultMap = new HashMap<>();

        String str = environment.getProperty("app.info.str");
        String date = environment.getProperty("app.info.date");
        String array2 = environment.getProperty("app.info.array2");
        String arrayToList = environment.getProperty("app.info.arrayToList");
        String cityMap = environment.getProperty("app.info.cityMap");
        String xxx = environment.getProperty("app.info.xxx");

        resultMap.put("str", str);
        resultMap.put("date", date);
        resultMap.put("array2", array2);
        resultMap.put("arrayToList", arrayToList);
        resultMap.put("cityMap", cityMap);
        resultMap.put("xxx", xxx);

        // {
        // 	"str": "张三",
        // 	"date": "2018/07/11",
        // 	"cityMap": "{\"mapK1\": \"长沙麓谷\",\"mapK2\": \"深圳科技园\"}",
        // 	"arrayToList": "唐,宋,元,明,清",
        // 	"array2": "a,b,c,d,e"
        // }
        return resultMap;
    }

    /**
     * 批量查询全局配置文件的属性值
     * {@link Environment} 表示环境, 可用于获取应用程序的属性配置.
     * String getProperty(String key, String defaultValue): 返回全局配置文件中与给定 key 关联的属性值, 如果没有,则返回 defaultValue.
     * <p>
     * http://localhost:8080/value/environment2
     *
     * @param keyList: 全局配置文件中的属性值集合
     *                 如: ["author.addr","author.age","author.city","author.id","author.like","author.userName","author.color","author.height","author.port"]
     * @return :返回批量查询全局配置文件的属性值
     */
    @PostMapping("value/environment2")
    public Map<String, Object> environment2(@RequestBody List<String> keyList) {
        Map<String, Object> resultMap = new LinkedHashMap<>(keyList.size() + 8);
        for (String key : keyList) {
            String value = environment.getProperty(key, "");
            resultMap.put(key, value);
        }
        return resultMap;
    }

}
